(function (fruit, util) {
//#6DCEEC
    var _util = fruit.graphic.util;
    var ICON = fruit.graphic.TopologyICON;

    var text_opacity = 1;


    fruit.define("fruit.graphic.TopologyNode", {
        events: ['Updating', 'SelectNode', 'OverNode', 'OutNode', 'DragNodeStart', 'DragNode', 'DragNodeEnd'],
        properties: {
            size: {
                value: 48
            },
            scale: {
                value: 1,
                observable: true
            },
            isSelected: {
                value: false
            },
            fontSize: {
                value: 12
            },
            labelPath: {
                setter: function (value) {
                    this._labelPath = value;
                    this.setLabel();
                },
                getter: function () {
                    return this.labelPath;
                }
            }
        },
        methods: {
            init: function (inVertex, inContext) {
                var self = this;
                var vertex = this.vertext = inVertex;
                var data = this.data = vertex.data;
                var context = this.context = inContext;
                var xScale = this.xScale = context.xScale;
                var yScale = this.yScale = context.yScale;
                var element = this.element = _util.create("g")
                    .attr("pointer-events", "all")
                    .classed("node", true)
                    .attr("id", function () {
                        return data.id;
                    });

                this.bg = element.append("svg:rect").attr("fill", "transparent").attr("height", "30");//
                this.dot = element.append("svg:circle").attr("r", 10).classed("node_dot", true)
                this.img = element.append("svg:circle").attr("fill", "transparent");

                var text = this.text = this.element.append("svg:text")
                    .classed("label", true)
                    .style({
                        'visibility': 'hidden',
                        'opacity': text_opacity
                    });

                if (context.nodeDraggable()) {
                    var DragNode = d3.behavior.drag()
                        .on("dragstart", function () {
                            self.isdragging = true;
                            self.fire('SelectNode',self);
                            self.fire('DragNodeStart',self);
                            self.fire('Updating');
                        })
                        .on("drag", function () {
                            if (self.isdragging) {
                                data.x = data.x - xScale.invert(0) + xScale.invert(d3.event.dx);
                                data.y = data.y - yScale.invert(0) + yScale.invert(d3.event.dy);
                                // self.dragging();
                                self.fire('Updating');
                                self.fire('DragNode');
                            }
                        })
                        .on("dragend", function () {
                            self.isdragging = null;
                            self.fire('DragNodeEnd');
                        });
                    element.call(DragNode);
                }

                this.element
                    .on("mouseover", function (event) {
                        self.mouseover(event);
                    })
                    .on("mouseout", function (event) {
                        self.mouseout(event);
                    })
                    .on("click", function () {
                        //self.fire('SelectNode', self);
                    });
                //
                this.setLabel();
            },
            mouseover: function (event) {
                var element = this.element;
                var inEvent = d3.event;
                var target, related;
                target = inEvent.target;
                related = inEvent.relatedTarget;
                if (target && !fruit.dom.contains(element.node(), related) && target !== related) {
                    // l.l(1)
                    this.fire("OverNode", this);
                }
                d3.event.stopPropagation();
                d3.event.preventDefault();
                return false;
            },
            mouseout: function (event) {
                var inEvent = d3.event;
                var target, related;
                target = inEvent.target;
                related = inEvent.relatedTarget;
                var element = this.element;

                if (!fruit.dom.contains(element.node(), related) && target !== related) {
                   // l.l(related, target, element.node(), fruit.dom.contains(element.node(), related), d3.event);
                    this.fire("OutNode", this);
                }
                d3.event.stopPropagation();
                d3.event.preventDefault();
                return false;
            },

            bound: function (force) {
                if (!this._bound || this._bound.width == 0 || force) {
                    this._bound = this.element.node().getBBox();
                }
                return this._bound;
            },
            position: function () {
                var data = this.data;
                var xScale = this.context.xScale;
                var yScale = this.context.yScale;
                return {
                    x: xScale.get(data.x),
                    y: yScale.get(data.y)
                }
            },
            label: function () {
                return this._label || "";
            },
            setICON: function (forece) {
                if (forece || !this.iconType) {
                    var type;
                    var self = this;
                    var data = this.data;
                    var context = this.context;
                    var element = this.element;
                    var iconType = this.iconType = context.iconTypePath();
                    if (iconType) {
                        if (util.isFunction(iconType)) {
                            type = iconType.call(this, data, this);
                        } else {
                            type = util.getByPath(iconType, data) || iconType;
                        }
                    } else {
                        type = data.type;
                    }
                    type = this.iconType = (type || "default").toLowerCase();

                    var icon = this.icon = ICON.getICON(type);
                    if (this.img) {
                        this.img.remove();
                    }
                    var img = this.img = element.appendDOM(icon.icon.cloneNode(true));
//                    img.on("click", function () {
//                        self.fire('SelectNode', self);
//                    });

//                    img
//                        .on("mouseout", function () {
//                            self.mouseover();
//                        })
//                        .on("mouseover", function () {
//                            self.mouseout();
//                        });
                    //
                    element.attr("type", type);
                    this.invertImg(context.highContrast());
                }

            },
            invertImg: function (value) {
                if (value && this.img) {
                    if (fruit.browser.firefox) {
                        this.img.style("filter", "invert(1)");
                    } else {
                        this.img.style("filter", "url(#invert)");
                    }
                } else {
                    this.img.style("filter", "");
                }
            },
            setHint: function (text, bgColor, node_color) {
                if (text) {
                    var bound;
                    if (!this.hint) {
                        this.hint_bg = this.element.append("svg:rect").classed("hint_bg", true).attr("fill", bgColor || "url(#hint_bg)");
                        this.hint = this.element.append("svg:text").classed("hint", true).attr("fill", node_color || "#333");
                    }
                    this.hint.text(text).style("display", "block");
                    bound = this.hint.node().getBBox();
                    this.hint_bg.attr({
                        width: bound.width + 12,
                        height: bound.height + 4,
                        rx: 2,
                        ry: 2
                    }).style("display", "block");
                    this.redraw();
                } else {
                    if (this.hint) {
                        this.hint.style("display", "none");
                        this.hint_bg.style("display", "none");
                        //this.hint = null;
                    }
                }
            },

            setLabel: function () {
                var label;
                var inLabel = this.context.nodeLabelPath();
                if (util.isFunction(inLabel)) {
                    label = this._label = inLabel.call(this, this.data, this);
                } else if (inLabel == "none") {
                    label = "";
                } else {
                    label = this._label = util.getByPath(inLabel, this.data) || this.data.id;
                }

                this.text.text(label);
                util.delay(util.bind(this.__centerlizeText, this), 0)
            },
            enlarge: function () {
                var scale = this.scale();
                var size = this.size() * scale;
                var img = this.img;
                var position = this.position();
                this._large = true;
                this.isdragging = false;
                this.img
                    .transition()
                    .duration(150)
                    //.ease("elastic")
                    .attr("width", size + 10)
                    .attr("height", size + 10)
                    .attr("x", position.x - size / 2 - 5)
                    .attr("y", position.y - size / 2 - 5);
            },
            shrink: function () {
                if (this._large) {
                    var scale = this.scale();
                    var size = this.size() * scale;
                    var position = this.position();
                    var img = this.img;
                    img
                        .transition()
                        .duration(250)
                        .attr("width", size)
                        .attr("height", size)
                        .attr("x", position.x - size / 2)
                        .attr("y", position.y - size / 2);
                    this._large = false;
                    this.isdragging = true;
                }
            },
            highLight: function (inColor) {
                var defaultBGColor = "#6DCEEC";
                var icon_bg = this.img.select(".bg");
                icon_bg.attr("fill", inColor || defaultBGColor);
            },
            selected: function () {
                this.element.style("opacity", 1);
                this.text.style("opacity", 1);
                this.isSelected(true);
            },
            unSelected: function () {
                this.isSelected(false);
            },
            fadeIn: function (force) {
                this.shrink();
                if (!this._fade || force) {
                    this.element.style("opacity", 1);
                    this.text.style("opacity", text_opacity);
                    this._fade = false;
                } else {
                    this.fadeOut();
                }
            },
            fadeOut: function (force) {
                if (force) {
                    this._fade = true;
                }
                this.element.style("opacity", 0.3);
            },
            zoom: function (scale) {
                if (scale == 1) {
                    this.setICON();
                    this.img.style("display", "block");
                    this.dot.style("display", "none");
                    this.fontSize(12);
                    this.size(this.icon.size);
                    this.redraw();
                    this.bound(true);
                } else {
                    this.img && this.img.style("display", "none");
                    this.dot.style("display", "block");
                    this.fontSize(Math.floor(6 + 5 * scale));
                    this.size(24 * scale);
                    this.dot.attr("r", 12 * scale);
                    this.redraw();
                    this.bound(true);
                }
            },
            dragging: function () {
                this.redraw();
                this.eachLink(function (link) {
                    link.redraw();
                })
            },
//            delineation: function (inColor) {
//                var self = this;
//                var i = 0;
//                var size = this.size();
//                var color = inColor || "#15B3FF";
//                //
//                this.arc = d3.svg.arc()
//                    .startAngle(0)
//                    .innerRadius(size / 2 - 3)
//                    .outerRadius(size / 2 + 0);
//                this.circle = element.append("path");
//                //animation
//                (function () {
//                    self.circle
//                        .style("fill", color)
//                        .attr("d", self.arc.endAngle(++i / 9 * Math.PI));
//                    if (i < 18) {
//                        setTimeout(arguments.callee, 10);
//                    }
//                })();
//            },
//            unDelineation: function () {
//                var self = this;
//                var i = 18;
//                (function () {
//                    self.circle.attr("d", self.arc.endAngle(--i / 9 * Math.PI));
//                    if (i > 0) {
//                        setTimeout(arguments.callee, 5);
//                    }
//                })();
//            },
            hide: function () {
                this.element.style("opacity", 0);
            },
            node: function () {
                return this.element.node();
            },
            links: function () {
                var self = this;
                var links = [];
                this.vertext.eachEdge(function (link) {
                    if (link.id) {
                        links.push(self.context.getEdge(link.id))
                    }
                });
                return links;
            },
            eachLink: function (fn) {
                var self = this;
                this.vertext.eachEdge(function (link) {
                    if (link.id) {
                        var _link = self.context.getLink(link.id);
                        if (_link) {
                            fn.call(self, _link);
                        }

                    }
                });
            },
            redraw: function () {
                var self = this;
                var data = this.data;
                var scale = 0.5 + this.context.scale() / 2;
                this.scale(scale);
                var size = this.size() * scale;
                var xScale = this.context.xScale;
                var yScale = this.context.yScale;
                var x = xScale.get(data.x);
                var y = yScale.get(data.y);

                this.img && this.img.attr("x", x - size / 2 || 0)
                    .attr("y", y - size / 2 || 0)
                    .attr("width", size)
                    .attr("height", size);
                this.bg
                    .attr("x", x - size / 2 || 0)
                    .attr("y", y - size / 2 || 0)
                    .attr("width", size)
                    .attr("height", size);
                this.dot.attr("cx", x)
                    .attr("cy", y);
                this.text.attr("x", x)
                    .attr("y", y)
                    .style({
                        // 'visibility': 'hidden'
                    });

                if (this.hint) {
                    this.hint.attr("x", x + size / 2 + 6).attr("y", y - size / 2 + 6);
                    this.hint_bg.attr("x", x + size / 2).attr("y", y - size / 2 - 8);

                }


                if (this._centerlizeTextTimer) {
                    clearTimeout(this._centerlizeTextTimer)
                }
                this._centerlizeTextTimer = setTimeout(function () {
                    self.__centerlizeText();
                }, 30);
            },
            __centerlizeText: function () {
                var self = this;
                var coordinate = [0, 0, 0, 0];//[top,right,bottom,left]

                var scale = 0.5 + this.context.scale() / 2;
                var size = this.size() * scale;
                var height = size * scale / 2 + 8;
                this.eachLink(function (link) {
                    var linkPosition = link.position();
                    var nodePosition = self.position();

                    var x_len = linkPosition.x2 - linkPosition.x1;
                    var y_len = linkPosition.y2 - linkPosition.y1;
                    var rate = Math.abs(y_len) > Math.abs(x_len) ? 1 : 0;

                    if (linkPosition.x1 == nodePosition.x && linkPosition.y1 == nodePosition.y) {
                        if (rate) {
                            rate = linkPosition.y2 <= nodePosition.y ? -1 : 1;
                        } else {
                            rate = linkPosition.x2 < nodePosition.x ? 2 : 0;
                        }
                    } else {
                        if (rate) {
                            rate = linkPosition.y1 <= nodePosition.y ? -1 : 1;
                        } else {
                            rate = linkPosition.x1 < nodePosition.x ? 2 : 0;
                        }
                    }

                    coordinate[rate + 1] += 1;

                });
                var min = util.min(coordinate);
                var textDirection, offsetX, offsetY;
                var labelPositionOrder = this.context.labelPositionOrder();
                textDirection = util.find(labelPositionOrder, function (num) {  //[bottom,top,right,left]
                    return min == coordinate[num];
                });


                this.text.style({
                    'visibility': 'visible',
                    'font-size': this.fontSize()
                });
                try {
                    var text_bbox = this.text.node().getBBox();
                } catch (e) {
                    return
                }

                if (text_bbox.width == 0) {
                    this.text_bbox = null;
                    return;
                }


                switch (textDirection) {
                    case 0: //'top'
                        offsetX = text_bbox.width / 2 * -1;
                        offsetY = size / -2 - 8;
                        break;
                    case 1: //'right'
                        offsetX = size / 2 + 3;
                        offsetY = 3;
                        break;
                    case 3: //'left'
                        offsetX = (text_bbox.width + size / 2 + 3) * -1;
                        offsetY = 3;
                        break;
                    default:
                        offsetX = text_bbox.width / 2 * -1;
                        offsetY = (size / 2 + 12);
                        break;
                }
                this.text
                    .attr("width", text_bbox.width)
                    .attr("transform", function () {
                        return "translate(" + offsetX + "," + offsetY + ")"
                    });
                this.text.attr("position", JSON.stringify(coordinate));
            }


        }

    })
})
    (fruit, fruit.util);